package com.vankimgps.services;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.GZIPInputStream;

import org.xmlpull.v1.XmlPullParserException;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class Services implements Runnable {
//	private static final String kHTTPHeader_DeviceID = "X-GNT-DEVID";
//	private static final String kHTTPHeader_DeviceType = "X-GNT-DEVTYPE";
//	private static final String kHTTPHeader_OSVersion = "X-GNT-OSVER";
//	private static final String kHTTPHeader_Hardware = "X-GNT-MODEL";
//	private static final String kHTTPHeader_AppVersion = "X-GNT-APPVER";
//	private static final String kHTTPHeader_UID = "X-GNT-UID";

	private static final String DOMAIN = "http://gps.vankim.net/api";
//	private static final String DOMAIN = "http://172.18.4.20:8088/api";

	private HttpURLConnection _connection;
	private ServiceAction _action;
	private ServiceListener _listener;
	private boolean _connecting;
	private Thread _thread;
	private String _actionURI;
	private Map<String, String> _params;
	private boolean _isGet;
	private Services _service;
	private boolean _isBitmap;

	public Services() {
		this(null);
	}

	// Handler
	final Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			_listener.onCompleted(_service, msg.obj);
		}
	};

	public Services(ServiceListener listener) {
		_action = ServiceAction.ActionNone;
		_listener = listener;
		_connecting = false;
		_service = this;
		_isBitmap = false;
	}

	public void testService(){
		_action = ServiceAction.ActionTestService;
		request(DOMAIN + "/testservice", null,true);		
	}
	
	public void login(String username, String password) {
		_action = ServiceAction.ActionLogin;
		Map<String, String> params = new HashMap<String, String>();
		params.put("username", username);
		params.put("password", password);
		request(DOMAIN + "/login", params, false);
	}

	public void logout(String token) {
		_action = ServiceAction.ActionLogout;
		Map<String, String> params = new HashMap<String, String>();
		params.put("token", token);
		request(DOMAIN + "/auth/logout", params, true);
	}

	public void getVehicles(String token, String UserID) {
		_action = ServiceAction.ActionGetAllVehicle;
		Map<String, String> params = new HashMap<String, String>();
		params.put("id", UserID);
		request(DOMAIN + "/vehicle/" + token , params, true);
	}

	public void getVehicleStatus(String token, String UserID) {
		_action = ServiceAction.ActionGetAllVehStatus;
		Map<String, String> params = new HashMap<String, String>();
		params.put("id", UserID);
		request(DOMAIN + "/newestposition/" + token , params, true);
	}

	public void setListener(ServiceListener listener) {
		_listener = listener;
	}

	public boolean isConnecting() {
		return _connecting;
	}

	private void cleanUp() {
		_action = ServiceAction.ActionNone;
		if (_connection != null) {
			try {
				_connection.disconnect();
			} catch (Exception ex) {
				// do nothing
			}
			_connection = null;
		}
		_connecting = false;
		Log.d("Service", "StopService");
	}

	public void stop() {
		cleanUp();
	}

//	private boolean request(String uri, Map<String, String> params) {
//		return request(uri, params, false);
//	}

	private boolean request(String uri, Map<String, String> params, boolean isGet) {
		if (_connecting)
			return false;
		_connecting = true;
		_actionURI = uri;
		_params = params;
		_isGet = isGet;
		_thread = new Thread(this);
		_thread.start();
		return true;
	}

	private String getParamsString(Map<String, String> params) {
		if (params == null)
			return null;
		String ret = "";
		
		int count = 1;
		
		for (String key : params.keySet()) {
			String value = params.get(key);
			if (count < params.size())
				ret += key + "=" + URLEncoder.encode(value) + "&";
			else
				ret += key + "=" + URLEncoder.encode(value);
			count++;
		}
		return ret;
	}

	private void processError(ResultCode errorCode) {
		if (_listener == null || _action == ServiceAction.ActionNone
				|| !_connecting)
			return;
		Message msg = handler.obtainMessage(0, new ServiceResponse(_action,
				null, errorCode));
		handler.sendMessage(msg);
	}

	private void dispatchResult(String result) throws XmlPullParserException, IOException {
		if (_listener == null || _action == ServiceAction.ActionNone
				|| !_connecting)
			return;
		ServiceAction act = _action;
		Object resObj = null;

		if (act == ServiceAction.ActionLogin) {
			resObj = DataParser.parseLogin(result);
		}else if (act == ServiceAction.ActionTestService){
			resObj = result;
		}else if (act == ServiceAction.ActionGetAllVehicle){
			resObj = DataParser.parseVehicle(result);
		}else if (act == ServiceAction.ActionGetAllVehStatus){
			resObj = DataParser.parseVehicleStatus(result);
		}		
		if (resObj == null) {
			resObj = new Object();
		}
		
		stop();
		Message msg = handler.obtainMessage(0, resObj);
		handler.sendMessage(msg);
	}

	private void dispatchResult(Bitmap result) {
		if (_listener == null || _action == ServiceAction.ActionNone
				|| !_connecting)
			return;
		ServiceAction act = _action;
		ServiceResponse response = null;
		if (result == null) {
			response = new ServiceResponse(act, null, ResultCode.Failed);
		} else {
			response = new ServiceResponse(act, result);
		}
		stop();
		Message msg = handler.obtainMessage(0, response);
		handler.sendMessage(msg);
	}

	public void run() {
		try {
			String urlString = _actionURI;
			String data = getParamsString(_params);
//			if (data == null)
//				data = "";
			if (_isGet) {
				urlString = urlString + "?" + data;
			}

			URL url = new URL(urlString);
			_connection = (HttpURLConnection) url.openConnection();
			_connection.setRequestMethod(_isGet ? "GET" : "POST");
			_connection.setDoInput(true);

			Log.i("VANKIM","VANKIM URL: " + url);

			if (!_isGet) {
				_connection.setDoOutput(true);
				try {
					OutputStream out = new BufferedOutputStream(
							_connection.getOutputStream());
					out.write(data.getBytes());		
					out.flush();
					out.close();
				} catch (IOException ioe) {
					throw ioe;
				}
			}

			int httpCode = _connection.getResponseCode();
			if (httpCode == HttpURLConnection.HTTP_OK) {
				InputStream in;
				if (_connection.getHeaderField("Content-encoding") != null
						&& _connection.getHeaderField("Content-encoding")
								.trim().toLowerCase().equals("gzip")) {
					in = new GZIPInputStream(_connection.getInputStream());
				} else {
					in = new BufferedInputStream(_connection.getInputStream());
				}
				if (_isBitmap) {
					Bitmap bm = BitmapFactory.decodeStream(in);
					dispatchResult(bm);
				} else {
					StringBuffer text = new StringBuffer();
					byte buff[] = new byte[1024];
					int c = 0;
					while ((c = in.read(buff)) > 0) {
						text.append(new String(buff, 0, c, "UTF-8"));
					}
					String temp = text.toString();
					dispatchResult(temp.toString());
				}

			} else if (httpCode == HttpURLConnection.HTTP_NOT_FOUND) {
				processError(ResultCode.Failed);
			} else if (httpCode == HttpURLConnection.HTTP_SERVER_ERROR) {
				processError(ResultCode.ServerError);
			} else {
				processError(ResultCode.NetworkError);
			}
		} catch (Exception ex) {
			Log.e("Service", ex.toString());
			processError(ResultCode.NetworkError);
		} finally {
			cleanUp();
		}
	}
}
